package com.zdp.netty.chapter14.server;

import com.zdp.netty.chapter14.MessageType;
import com.zdp.netty.chapter14.struct.Header;
import com.zdp.netty.chapter14.struct.NettyMessage;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author zhengdp
 * @Description 服务端进行登录校验，重复登录判断 + IP白名单判断
 */
public class LoginAuthRespHandler extends ChannelHandlerAdapter {

    private Map<String, Boolean> nodeCheck = new ConcurrentHashMap<String, Boolean>();

    private String[] whiteList = {"127.0.0.1"};

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        NettyMessage message = (NettyMessage) msg;

        // 处理握手消息
        if (Objects.nonNull(message.getHeader()) && Objects.equals(message.getHeader().getType(), MessageType.LOGIN_REQ.getValue())) {
            String nodeIndex = ctx.channel().remoteAddress().toString();
            NettyMessage loginResp = null;
            // 重复登录判断
            if(nodeCheck.containsKey(nodeIndex)) {
                loginResp = buildResponse((byte) -1);
            } else {
                // 白名单判断
                InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = address.getAddress().getHostAddress();
                boolean isOk = Arrays.stream(whiteList).anyMatch(WIP -> StringUtils.equals(WIP,ip));
                loginResp = isOk ? buildResponse((byte)0) : buildResponse((byte) -1);
                if(isOk) {
                    nodeCheck.put(nodeIndex,true);
                }
            }
            System.out.println("The login response is : " + loginResp + " body [ " + loginResp.getBody() + "]");
            ctx.writeAndFlush(loginResp);
        } else {
            // 释放消息，以便链上的下一个Handler可以处理
            ctx.fireChannelRead(msg);
        }
    }

    private NettyMessage buildResponse(byte result) {
        NettyMessage message = new NettyMessage();
        Header header = new Header();
        header.setType(MessageType.LOGIN_RESP.getValue());
        message.setBody(result);
        message.setHeader(header);
        return message;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        nodeCheck.remove(ctx.channel().remoteAddress().toString());
        ctx.close();
        ctx.fireExceptionCaught(cause);
    }
}
